<script setup>
import { onMounted, ref } from "vue";
import * as THREE from "three";
//import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

const props = defineProps({ data: Object });

const container = ref(null);

onMounted(async () => {
  const { OrbitControls } = await import(
    "three/examples/jsm/controls/OrbitControls.js"
  );
  // 初始化场景
  const scene = new THREE.Scene();

  // 初始化相机
  const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );
  camera.position.z = 5;

  // 初始化渲染器
  const renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 启用阴影
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  container.value.appendChild(renderer.domElement);

  // 初始化控制器
  const controls = new OrbitControls(camera, renderer.domElement);

  // 增强环境光强度
  const ambientLight = new THREE.AmbientLight(0x606060);
  scene.add(ambientLight);

  // 增强点光源强度
  const pointLight = new THREE.PointLight(0xffffff, 2, 100);
  pointLight.position.set(5, 5, 5);
  pointLight.castShadow = true;
  scene.add(pointLight);

  // 定义 time 变量
  let time = 0;

  const nodes = new Map();
  const halos = new Map();
  const lines = new Map();
  const sprites = new Map();
  // 定义光晕着色器
  const haloShader = {
    vertexShader: `
      varying vec3 vNormal;
      void main() {
        vNormal = normalize( normalMatrix * normal );
        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
      }
    `,
    fragmentShader: `
      varying vec3 vNormal;
      uniform vec3 glowColor;
      uniform float coeficient;
      uniform float power;
      void main() {
        // 调整计算方式，让光晕过渡更柔和
        float intensity = pow( max(0.0, coeficient - dot( vNormal, vec3( 0.0, 0.0, 1.0 ) )), power );
        gl_FragColor = vec4( glowColor, intensity );
      }
    `,
  };

  const flightMarkers = new Map(); // 存储所有飞行标记

  // 递归函数创建树节点
  // 在createNode函数中添加轨道参数初始化
  function createNode(
    data,
    parent = null,
    position = new THREE.Vector3(0, 0, 0)
  ) {
    // 检查 data 是否存在
    if (!data) {
      return;
    }
    // 增加根节点的半径
    const geometry = new THREE.SphereGeometry(
      data.id === 1 ? 0.3 : 0.2, // 增大节点尺寸
      32,
      32
    );

    // 使用更柔和的颜色
    const pastelColors = [
      0x8dd3c7, 0xffffb3, 0xbebada, 0xfb8072, 0x80b1d3, 0xfdb462, 0xb3de69,
      0xfccde5, 0xd9d9d9, 0xbc80bd,
    ];

    // 设置根节点颜色为蓝色，其他节点使用柔和的颜色
    const color =
      data.id === 1
        ? 0x4169e1
        : pastelColors[Math.floor(Math.random() * pastelColors.length)];

    const material = new THREE.MeshStandardMaterial({
      color: color,
      metalness: data.id === 1 ? 0.5 : 0.3, // 根节点增加金属感
      roughness: data.id === 1 ? 0.1 : 0.2, // 根节点降低粗糙度，增加光泽
      emissive: new THREE.Color(color).multiplyScalar(
        data.id === 1 ? 1.2 : 0.8
      ), // 根节点发光强度提高
      emissiveIntensity: data.id === 1 ? 1.5 : 1.0, // 为根节点添加发光强度
      opacity: 0.9, // 增加不透明度
    });
    const node = new THREE.Mesh(geometry, material);
    console.log(position);
    node.position.copy(position);
    node.castShadow = true;
    node.receiveShadow = true;
    node.userData.isNode = true;
    scene.add(node);

    // 将节点存入nodes集合
    nodes.set(data, {
      node: node,
      parent: parent ? parent.uuid : null,
      initialOffset: position.clone(),
      orbitParams: {
        semiMajorAxis: 0.8 + Math.random() * 0.4, // 增大轨道半径
        semiMinorAxis: 0.6 + Math.random() * 0.3, // 增大轨道半径
        revolutionSpeed: 0.03 + Math.random() * 0.05, // 减慢公转速度
      },
    });

    if (parent) {
      // 直接使用父节点和当前节点位置创建直线
      const points = [parent.position, position];
      const lineGeometry = new THREE.BufferGeometry().setFromPoints(points);
      const lineMaterial = new THREE.LineBasicMaterial({
        color: 0xcccccc, // 使用浅灰色连线
        linewidth: 1, // 减小线宽
        transparent: true,
        opacity: 0.6, // 增加透明度
      });
      const line = new THREE.Line(lineGeometry, lineMaterial);
      lines.set(node.uuid, line);
      scene.add(line);

      // 创建飞行标记
      const markerGeometry = new THREE.ConeGeometry(0.04, 0.1, 32); // 调小尺寸
      const markerMaterial = new THREE.MeshStandardMaterial({
        color: 0xffffff, // 使用白色标记
        emissive: new THREE.Color(color), // 使用节点的颜色作为发光色
        emissiveIntensity: 0.5,
        transparent: true,
        opacity: 0.8,
      });
      const marker = new THREE.Mesh(markerGeometry, markerMaterial);
      marker.rotation.x = Math.PI / 2;
      marker.position.copy(parent.position);
      scene.add(marker);

      // 存储父节点和当前节点的引用，而不是固定位置
      flightMarkers.set(node.uuid, {
        marker: marker,
        progress: 0,
        points: [parent.position, node.position], // 使用节点引用
        speed: 0.005 + Math.random() * 0.01,
      });
    }

    if (data.children) {
      // 更均匀地分布子节点
      const childCount = data.children.length;
      data.children.forEach((child, index) => {
        // 计算子节点在球面上的均匀分布位置
        const phi = Math.acos(-1 + (2 * index) / childCount);
        const theta = Math.sqrt(childCount * Math.PI) * phi;

        // 使用球面坐标系创建更均匀的分布
        const radius = 2 + Math.random() * 0.8; // 子节点距离
        const x = radius * Math.sin(phi) * Math.cos(theta);
        const y = radius * Math.sin(phi) * Math.sin(theta);
        const z = radius * Math.cos(phi);
        const childPosition = new THREE.Vector3(
          position.x + x,
          position.y + y,
          position.z + z
        );

        createNode(child, node, childPosition);
      });
    }

    // 创建光晕
    const haloGeometry = new THREE.SphereGeometry(
      data.id === 1 ? 0.4 : 0.25, // 调小光晕尺寸
      32,
      32
    );
    const haloMaterial = new THREE.ShaderMaterial({
      uniforms: {
        coeficient: { value: data.id === 1 ? 0.18 : 0.15 }, // 微调光晕系数
        power: { value: data.id === 1 ? 0.4 : 0.5 }, // 保持功率值
        glowColor: {
          value: new THREE.Color(color).multiplyScalar(
            data.id === 1 ? 0.5 : 0.3
          ), // 保持颜色亮度
        },
      },
      vertexShader: haloShader.vertexShader,
      fragmentShader: haloShader.fragmentShader,
      side: THREE.BackSide,
      blending: THREE.AdditiveBlending,
      transparent: true,
    });
    const halo = new THREE.Mesh(haloGeometry, haloMaterial);
    halo.position.copy(position);
    scene.add(halo);
    halos.set(data, halo);
    // 创建文字标签
    const canvas = document.createElement("canvas");
    canvas.width = 400; // 设置画布宽度
    canvas.height = 200; // 设置画布高度
    const context = canvas.getContext("2d");
    context.font = "24px Arial";
    context.fillStyle = "white";
    context.textAlign = "center";
    context.textBaseline = "middle";
    context.fillText(data.name, canvas.width / 2, canvas.height / 2);

    const texture = new THREE.CanvasTexture(canvas);
    const spriteMaterial = new THREE.SpriteMaterial({
      map: texture,
      opacity: 1.0,
      depthTest: false,
      depthWrite: false,
      sizeAttenuation: false,
      renderOrder: 999,
    });
    const sprite = new THREE.Sprite(spriteMaterial);
    sprite.scale.set(0.5, 0.25, 1); // 适当调整标签大小
    // 将文字标签放在节点正上方并居中
    sprite.position.copy(position).add(new THREE.Vector3(0, 0.6, 0));
    scene.add(sprite);
    sprites.set(data, sprite);
  }

  // 移除新增粒子系统相关代码
  // 创建根节点
  let nodeData = props.data;
  nodeData.id = 1;
  createNode(nodeData);

  // 创建星空背景
  const starGeometry = new THREE.BufferGeometry();
  const starCount = 1000; // 从5000减少到2000
  const positions = new Float32Array(starCount * 3);
  const colors = new Float32Array(starCount * 3);
  const sizes = new Float32Array(starCount);

  for (let i = 0; i < starCount; i++) {
    const i3 = i * 3;
    // 扩大星空范围
    positions[i3] = (Math.random() - 0.5) * 1000;
    positions[i3 + 1] = (Math.random() - 0.5) * 1000;
    positions[i3 + 2] = (Math.random() - 0.5) * 1000;

    // 随机星星颜色，偏向蓝白色调
    const shade = 0.8 + Math.random() * 0.2; // 0.8-1.0之间的亮度
    colors[i3] = shade;
    colors[i3 + 1] = shade;
    colors[i3 + 2] = shade + Math.random() * 0.1; // 蓝色通道略高

    // 随机星星大小
    sizes[i] = Math.random() * 2; // 0-2之间的大小
  }

  starGeometry.setAttribute(
    "position",
    new THREE.BufferAttribute(positions, 3)
  );
  starGeometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
  starGeometry.setAttribute("size", new THREE.BufferAttribute(sizes, 1));

  // 创建自定义着色器材质，使用自定义着色器让星星发光
  const starVertexShader = `
    attribute float size;
    varying vec3 vColor;
    void main() {
      vColor = color;
      vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
      gl_PointSize = size * (300.0 / -mvPosition.z);
      gl_Position = projectionMatrix * mvPosition;
    }
  `;

  const starFragmentShader = `
    varying vec3 vColor;
    void main() {
      // 创建圆形点
      float r = 0.5;
      vec2 uv = gl_PointCoord - vec2(0.5);
      float d = length(uv);

      // 发光效果
      float strength = 1.0 - d;
      strength = pow(strength, 2.0);

      // 应用颜色和发光
      vec3 glow = vColor * strength * 1.5;
      gl_FragColor = vec4(glow, strength);
    }
  `;

  const starMaterial = new THREE.ShaderMaterial({
    uniforms: {},
    vertexShader: starVertexShader,
    fragmentShader: starFragmentShader,
    blending: THREE.AdditiveBlending,
    depthTest: false,
    transparent: true,
    vertexColors: true,
  });

  const starField = new THREE.Points(starGeometry, starMaterial);
  scene.add(starField);

  // 添加一些较大的亮星
  const brightStarGeometry = new THREE.BufferGeometry();
  const brightStarCount = 30; // 从50减少到30
  const brightStarPositions = new Float32Array(brightStarCount * 3);
  const brightStarSizes = new Float32Array(brightStarCount);
  const brightStarColors = new Float32Array(brightStarCount * 3);

  for (let i = 0; i < brightStarCount; i++) {
    const i3 = i * 3;
    brightStarPositions[i3] = (Math.random() - 0.5) * 800;
    brightStarPositions[i3 + 1] = (Math.random() - 0.5) * 800;
    brightStarPositions[i3 + 2] = (Math.random() - 0.5) * 800;
    brightStarSizes[i] = 2.5 + Math.random() * 3; // 更大的亮星

    // 亮星颜色偏蓝白色
    brightStarColors[i3] = 0.9;
    brightStarColors[i3 + 1] = 0.9;
    brightStarColors[i3 + 2] = 1.0;
  }

  brightStarGeometry.setAttribute(
    "position",
    new THREE.BufferAttribute(brightStarPositions, 3)
  );
  brightStarGeometry.setAttribute(
    "size",
    new THREE.BufferAttribute(brightStarSizes, 1)
  );
  brightStarGeometry.setAttribute(
    "color",
    new THREE.BufferAttribute(brightStarColors, 3)
  );

  const brightStarMaterial = new THREE.ShaderMaterial({
    uniforms: {},
    vertexShader: starVertexShader,
    fragmentShader: starFragmentShader,
    blending: THREE.AdditiveBlending,
    depthTest: false,
    transparent: true,
    vertexColors: true,
  });

  const brightStarField = new THREE.Points(
    brightStarGeometry,
    brightStarMaterial
  );
  scene.add(brightStarField);

  // 修改 animate 函数，移除粒子系统更新部分
  function animate() {
    requestAnimationFrame(animate);
    controls.update();
    time += 0.01;

    flightMarkers.forEach((markerData, nodeId) => {
      const { marker, points, speed } = markerData;
      markerData.progress += speed;

      if (markerData.progress > 1) {
        markerData.progress = 0;
      }

      // 获取父节点和当前节点的实时位置
      const parentPos = points[0];
      const currentPos = points[1];

      // 计算当前位置，使用实时位置而不是固定点
      const position = new THREE.Vector3();
      position.lerpVectors(parentPos, currentPos, markerData.progress);
      marker.position.copy(position);

      // 计算朝向，使用实时方向
      const direction = new THREE.Vector3()
        .subVectors(currentPos, parentPos)
        .normalize();
      const up = new THREE.Vector3(0, 1, 0);
      const quaternion = new THREE.Quaternion();
      quaternion.setFromUnitVectors(up, direction);
      marker.quaternion.copy(quaternion);
    });
    nodes.forEach(
      ({ node, parent: parentId, orbitParams, initialOffset }, data) => {
        if (parentId) {
          const parentEntry = [...nodes].find(
            ([_, value]) => value.node.uuid === parentId
          );
          if (parentEntry) {
            const parentPosition = parentEntry[1].node.position;
            const angle = time * orbitParams.revolutionSpeed;

            // 围绕父节点进行旋转运动，y 轴使用节点初始 Y 轴值
            let x =
              parentPosition.x -
              initialOffset.x +
              orbitParams.semiMajorAxis * Math.cos(angle);
            const y =
              parentPosition.y -
              initialOffset.y +
              orbitParams.semiMinorAxis * Math.cos(angle);
            const z = initialOffset.z + 0.5 * Math.sin(angle * 2);
            // 添加入场动画，使用线性插值
            const targetPosition = new THREE.Vector3(x, y, z);
            node.position.lerp(targetPosition, 0.1); // 0.1 是插值因子，可以调整以改变动画速度
            // Update line positions and colors within this block
            const line = lines.get(node.uuid);
            if (line) {
              line.geometry.setFromPoints([
                parentEntry[1].node.position,
                node.position,
              ]);
              line.geometry.verticesNeedUpdate = true;
              line.material.color.setHSL(
                Math.sin(time * 0.5) * 0.5 + 0.5,
                0.9,
                0.7
              );
            }
          }
        }

        // 节点旋转动画，减小旋转增量值
        node.rotation.x += 0.5;
        node.rotation.y += 0.5;

        // 光晕呼吸效果
        const halo = halos.get(data);
        if (halo) {
          halo.position.copy(node.position);
          // 调整光晕呼吸效果幅度
          const scale =
            data.id === 1
              ? 1 + 0.15 * Math.sin(time * 2) // 减小根节点光晕呼吸幅度
              : 1 + 0.1 * Math.sin(time * 2); // 减小普通节点光晕呼吸幅度
          halo.scale.set(scale, scale, scale);
        }
        // 更新文字标签位置
        const sprite = sprites.get(data);
        if (sprite) {
          sprite.position.copy(node.position);
        }
      }
    );
    // 添加星星闪烁效果
    const sizes = starGeometry.attributes.size.array;
    for (let i = 0; i < sizes.length; i++) {
      // 使用柔和的正弦波让星星闪烁更自然
      sizes[i] = Math.max(0.1, Math.abs(Math.sin(time * 0.3 + i * 0.2)) * 2);
    }
    starGeometry.attributes.size.needsUpdate = true;

    // 亮星闪烁效果
    const brightSizes = brightStarGeometry.attributes.size.array;
    for (let i = 0; i < brightSizes.length; i++) {
      // 使用不同频率的正弦波，让亮星闪烁更明显
      brightSizes[i] = 2.5 + Math.sin(time * 0.5 + i * 0.3) * 1.5;
    }
    brightStarGeometry.attributes.size.needsUpdate = true;

    // 缓慢旋转星空，增加动态效果
    starField.rotation.y += 0.0001;
    brightStarField.rotation.y += 0.00008;
    starField.rotation.x += 0.00005;
    brightStarField.rotation.x += 0.00003;

    renderer.render(scene, camera);
  }

  animate();
  const raycaster = new THREE.Raycaster();
  const mouse = new THREE.Vector2();
  const tooltip = document.createElement("div");
  tooltip.style.position = "fixed";
  tooltip.style.background = "rgba(0, 0, 0, 0.7)";
  tooltip.style.color = "white";
  tooltip.style.padding = "10px 15px";
  tooltip.style.borderRadius = "4px";
  tooltip.style.display = "none";
  tooltip.style.maxWidth = "300px";
  tooltip.style.textAlign = "center";
  tooltip.style.transform = "translateX(-50%)";
  tooltip.style.left = "50%";
  tooltip.style.top = "calc(100% - 40px)";
  tooltip.style.zIndex = "1000";
  document.body.appendChild(tooltip);
  function onMouseMove(event) {
    // 获取鼠标在容器中的相对位置
    const rect = container.value.getBoundingClientRect();
    const x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
    const y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

    mouse.x = x;
    mouse.y = y;

    // 调整射线检测参数
    raycaster.params.Points.threshold = 0.1; // 减小检测阈值
    raycaster.params.Mesh = { threshold: 0 }; // 添加网格检测参数
    raycaster.far = 500; // 减小检测距离
    raycaster.near = 0.1; // 设置最小检测距离

    raycaster.setFromCamera(mouse, camera);
    const objectsToIntersect = [...nodes.values()].map((n) => n.node);

    const intersects = raycaster.intersectObjects(objectsToIntersect, true);

    if (intersects.length > 0) {
      const intersectedNode = intersects[0].object;
      const nodeData = [...nodes.entries()].find(
        ([data, { node }]) =>
          node === intersectedNode || node.uuid === intersectedNode.uuid
      );

      if (nodeData) {
        tooltip.style.display = "block";

        // 判断鼠标是否靠近底部（距离底部小于200px）
        const isNearBottom = window.innerHeight - event.clientY < 200;

        // 设置tooltip位置
        tooltip.style.left = `${event.clientX}px`;
        tooltip.style.top = isNearBottom
          ? `${event.clientY - 200}px` // 靠近底部时显示在上方
          : `${event.clientY + 30}px`; // 其他位置显示在下方

        tooltip.innerHTML = `<div style="margin-bottom:0;text-align: left;word-wrap: break-word;white-space: normal;">${
          nodeData[0].name
        }</div><br><div style="font-size: 12px;opacity:0.7;text-align: left;word-wrap: break-word;white-space: normal;margin-top:-20px;">${
          nodeData[0].task
        }</div><br><div style="font-size: 12px;opacity:0.7;text-align: left;word-wrap: break-word;white-space: normal;margin-top:-20px;">${
          nodeData[0].value ? nodeData[0].value : ""
        }</div>`;
      } else {
        tooltip.style.display = "none";
      }
    } else {
      tooltip.style.display = "none";
    }
  }

  window.addEventListener("mousemove", onMouseMove);
  // 窗口大小变化时更新
  window.addEventListener("resize", () => {
    // 获取容器的最新尺寸
    const width = container.value.clientWidth;
    const height = container.value.clientHeight;
    // 设置渲染器尺寸
    renderer.setSize(width, height);

    // 设置相机纵横比
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
  });
});
</script>

<template>
  <div ref="container" style="width: 100%; height: 100%"></div>
</template>
